home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 4 / Apprentice-Release4.iso / Source Code / Libraries / PNL Libraries / MySIVC.p < prev    next >
Encoding:
Text File  |  1995-10-24  |  11.8 KB  |  438 lines  |  [TEXT/CWIE]

  1. unit MySIVC;
  2.  
  3. interface
  4.  
  5.     uses
  6.         Types;
  7.  
  8.     const
  9.         PC_UseSIVC = 'SIVC';
  10.         PC_FirstCheckSIVC = 'SIVd';
  11.         PC_LastCheckSIVCQuantum = 'SICl';
  12.         PC_CheckSIVCPeriod = 'SIVc';
  13.         PC_LastSIVC = 'SIVL';
  14.         PC_SIVCUsers = 'SIVU';
  15.         
  16.     type
  17.         SIVCNewVersionCallBack = procedure(data:Handle; latest_version:Str31);
  18.         SIVCGetSOCKSServerCallBack = procedure(var server:Str255);
  19.         SIVCManualQueryCallBack = procedure(err:OSErr; newversion:Boolean; data:Handle; latest_version:Str31);
  20.     
  21.     var
  22.         first_ever_sivc: Boolean; { if this is the first time - warn the user! }
  23.         
  24.     procedure StartupSIVC;
  25.     procedure ConfigureSIVC(newversion : SIVCNewVersionCallBack; getsocks:SIVCGetSOCKSServerCallBack);
  26.         
  27.     procedure ManualQuery(mcresult: SIVCManualQueryCallBack);
  28.     function CanManualQuery:Boolean;
  29.     
  30. implementation
  31.  
  32.     uses
  33.         Errors, Resources, MyNewPreferences, MyTransport, DNR, MyMathUtils, TranslateISO,
  34.         MyTypes, MyHandleFile, MySocks, MyStrings, MyVersionResource, MyUtils, MyStartup;
  35.         
  36.     const
  37.         sivc_id = 932;
  38.         sivc_default_port = 7124;
  39.         idle_til_period = 10 * 60 *60; { only even consider checking every 10 minutes }
  40.         timeout_period = 120 * 60;
  41.  
  42.     type
  43.         SIVCStrings = (SS_None, SS_Server, SS_SOCKSServer);
  44.         SIVCState = (ST_None, ST_SOCKS_DNR, ST_Connecting, ST_SendSOCKS, ST_SendQuery, ST_WaitClose, ST_Finished);
  45.         SIVCMaunalState = (MS_None, MS_Want, MS_Doing);
  46.     
  47.     var
  48.         newversion_callback : SIVCNewVersionCallBack;
  49.         getsocks_callback : SIVCGetSOCKSServerCallBack;
  50.         mcresult_callback : SIVCManualQueryCallBack;
  51.         state : SIVCState;
  52.         tref: TransportRef;
  53.         idle_til:longint;
  54.         use_socks:boolean;
  55.         sivc_dnr:Ptr;
  56.         sivc_port:integer;
  57.         sivc_addr: IPAddr;
  58.         socks_port: integer;
  59.         vers:versionRecord;
  60.         app_creator: string[4];
  61.         query_result:Handle;
  62.         manual_state:SIVCMaunalState;
  63.         timeout:longint;
  64.     
  65.     procedure ServerToHostPort(s:Str255; defport:integer; var host:Str255; var port:integer);
  66.         var
  67.             portstr:Str255;
  68.             n:longint;
  69.     begin
  70.         if Split(':', s, host, portstr) | Split(' ', s, host, portstr) then begin
  71.             StringToNum(portstr,n);
  72.             port := n;
  73.         end else begin
  74.             host := s;
  75.             port := defport;
  76.         end;
  77.     end;
  78.     
  79.     procedure GetSOCKSServer(var server:Str255);
  80.     begin
  81.         server := '';
  82.         if getsocks_callback <> nil then begin
  83.             getsocks_callback(server);
  84.         end;
  85.         if server = '' then begin
  86.             GetIndString(server,sivc_id,ord(SS_SOCKSServer));
  87.         end;
  88.     end;
  89.     
  90.     procedure ReleaseConnection;
  91.     begin
  92.         TransportAbortDNR(sivc_dnr);
  93.         TransportDestroy(tref);
  94.     end;
  95.  
  96.     function SendQuery:OSErr;
  97.         var
  98.             query:Str255;
  99.             count:integer;
  100.             err: OSErr;
  101.     begin
  102.         if (manual_state = MS_Doing) then begin
  103.             query := 'Query: ProductInfoManual';
  104.         end else begin
  105.             query := 'Query: ProductInfoAuto';
  106.         end;
  107.         query := concat(query, cr,
  108.                                 'Product: ', vers.name, cr,
  109.                                 'ProductID: macos:APPL/',app_creator,cr,
  110.                                 'Version: ',HexNN(longint(vers.numericVersion),8),cr,
  111.                                 cr);
  112.         count := MacToNet(@query[1],length(query));
  113.         
  114.         err := TransportSend(tref, @query[1], count);
  115.         SendQuery := err;
  116.     end;
  117.     
  118.     function SendSocks:OSErr;
  119.         var
  120.             query:SocksRecordSmall;
  121.     begin
  122.         query.version := socks_version;
  123.         query.cmd := socks_connect;
  124.         query.port := sivc_port;
  125.         query.ip := sivc_addr;
  126.         SendSocks := TransportSend(tref, @query, SizeOf(query));
  127.     end;
  128.     
  129.     function IsField(field:Str255; var line:Str255):Boolean;
  130.         var
  131.             s:Str255;
  132.     begin
  133.         IsField := false;
  134.         if IsPrefix(line, field) then begin
  135.             s := Trim(TPCopy(line, length(field)+1, 255));
  136.             if (s<>'') & (s[1] = ':') then begin
  137.                 line := Trim(TPCopy(s, 2, 255));
  138.                 IsField := true;
  139.             end;
  140.         end;
  141.     end;
  142.     
  143.     procedure ProcessResult;
  144.         var
  145.             hf:HandleFile;
  146.             line:Str255;
  147.             latest_version:longint;
  148.             query_interval, users:longint;
  149.             ver:NumVersion;
  150.             new:boolean;
  151.     begin
  152.         hf.data := query_result;
  153.         hf.pos := 0;
  154.         hf.crlf := CL_CR;
  155.         hf.error := noErr;
  156.         latest_version := -1;
  157.         while ReadFromHandleFile(hf, line) do begin
  158.             if IsField('ReleaseVersion', line) then begin
  159.                 latest_version := HexToNum(line);
  160.             end else if IsField('AutoQueryIntervalM', line) then begin
  161.                 StringToNum(line, query_interval);
  162.                 if (query_interval >= 1440) & (query_interval < 136800) then begin { 1 to 95 days }
  163.                     prefs.SetTagLong(PC_CheckSIVCPeriod, query_interval);
  164.                 end;
  165.             end else if IsField('UserCount',line) then begin
  166.                 StringToNum(line, users);
  167.                 prefs.SetTagLong(PC_SIVCUsers, users);
  168.             end;
  169.         end;
  170.         new := (latest_version > longint(vers.numericVersion));
  171.         line := '';
  172.         if (latest_version <> -1) then begin
  173.             ver := NumVersion(latest_version);
  174.             line:=concat(NumToStr(ver.majorRev),'.',
  175.                                 NumToStr(BAND(ver.minorAndBugRev div 16,$0F)),'.',
  176.                                 NumToStr(BAND(ver.minorAndBugRev,$0F))
  177.                                 );
  178.             if (ver.stage<>$80) or (ver.nonRelRev<>0) then begin
  179.                 case ver.stage of 
  180.                     $20:begin
  181.                         line:=concat(line,'d');
  182.                     end;
  183.                     $40:begin
  184.                         line:=concat(line,'a');
  185.                     end;
  186.                     $60:begin
  187.                         line:=concat(line,'b');
  188.                     end;
  189.                     $80:begin
  190.                         line:=concat(line,'f');
  191.                     end;
  192.                     otherwise begin
  193.                         line:=concat(line,'<',NumToStr(ver.stage),'>');
  194.                     end;
  195.                 end;
  196.                 if ver.nonRelRev <> 0 then begin
  197.                     line:=concat(line,NumToStr(ver.nonRelRev));
  198.                 end;
  199.             end;
  200.         end;
  201.         if (manual_state = MS_Doing) then begin
  202.             if mcresult_callback <> nil then begin
  203.                 mcresult_callback(noErr, new, query_result, line);
  204.                 mcresult_callback := nil;
  205.             end;
  206.         end else begin
  207.             if new & (newversion_callback <> nil) then begin
  208.                 newversion_callback(query_result, line);
  209.             end;
  210.         end;
  211.     end;
  212.     
  213.     function GetThisQuantum:longint;
  214.         var
  215.             date,first_checked_date,check_period: longint;
  216.     begin
  217.         GetDateTime(date);
  218.         prefs.GetTagLong(PC_FirstCheckSIVC,first_checked_date);
  219.         prefs.GetTagLong(PC_CheckSIVCPeriod,check_period);
  220.         GetThisQuantum := (date - first_checked_date) div 60 div check_period;
  221.     end;
  222.     
  223.     procedure IdleSIVC;
  224.         var
  225.             last_quantum:longint;
  226.             s:Str255;
  227.             err:OSErr;
  228.             socksresult:SocksRecordSmall;
  229.             space: packed array[1..256] of byte;
  230.             count: integer;
  231.             tstate :TCPStateType;
  232.             date:longint;
  233.             received:longint;
  234.             result: OSStatus;
  235.             junk: OSErr;
  236.     begin
  237.         if (state <> ST_Finished) & ((manual_state <> MS_None) | (TickCount > idle_til)) then begin
  238.             err := noErr;
  239.             if (manual_state = MS_Want) & (state = ST_None) then begin
  240.                 manual_state := MS_Doing;
  241.             end;
  242.             if (state <> ST_None) & (state <> ST_SOCKS_DNR) & (TickCount > timeout) then begin
  243.                 err := -8;
  244.             end else if not prefs.GetTagBoolean(PC_UseSIVC) & (manual_state <> MS_Doing) then begin
  245.                 err := -4;
  246.             end else begin
  247.                 case state of
  248.                     ST_None: begin
  249.                         prefs.GetTagLong(PC_LastCheckSIVCQuantum,last_quantum);
  250.                         if (GetThisQuantum <> last_quantum) or (manual_state = MS_Doing) then begin
  251.                             SetHandleSize(query_result,0);
  252.                             GetSOCKSServer(s);
  253.                             use_socks := s<>'';
  254.                             GetIndString(s,sivc_id,ord(SS_Server));
  255.                             ServerToHostPort(s,sivc_default_port,s,sivc_port);
  256.                             if use_socks then begin
  257.                                 err := TransportNameToAddr(s, sivc_dnr);
  258.                                 state := ST_SOCKS_DNR;
  259.                             end else begin
  260.                                 timeout := TickCount + timeout_period;
  261.                                 err := TransportOpenActiveConnection(tref, concat(s, ':', NumToStr(sivc_port)), 0, 0);
  262.                                 if err = noErr then begin
  263.                                     err := TransportHandleTransfers(tref);
  264.                                 end;
  265.                                 state := ST_Connecting;
  266.                             end;
  267.                         end else begin
  268.                             err := -1;
  269.                         end;
  270.                     end;
  271.                     ST_SOCKS_DNR:begin
  272.                         TransportGetNameToAddrResult(sivc_dnr, result, nil, @sivc_addr, 1);
  273.                         case result of
  274.                             inProgress: begin
  275.                                 err := noErr;
  276.                             end;
  277.                             noErr: begin
  278.                                 timeout := TickCount + timeout_period;
  279.                                 GetSOCKSServer(s);
  280.                                 ServerToHostPort(s, socks_default_port, s, socks_port);
  281.                                 err := TransportOpenActiveConnection(tref, concat(s, ':', NumToStr(socks_port)), 0, 0);
  282.                                 if err = noErr then begin
  283.                                     err := TransportHandleTransfers(tref);
  284.                                 end;
  285.                                 state := ST_Connecting;
  286.                             end;
  287.                             otherwise begin
  288.                                 err := result;
  289.                             end;
  290.                         end;
  291.                     end;
  292.                     ST_Connecting:begin
  293.                         if not (TransportGetConnectionState(tref) in [T_WaitingForOpen, T_Bored, T_Opening]) then begin
  294.                             if TransportGetConnectionState(tref) = T_Established then begin
  295.                                 if use_socks then begin
  296.                                     err := SendSOCKS;
  297.                                     state := ST_SendSOCKS;
  298.                                 end else begin
  299.                                     err := SendQuery;
  300.                                     state := ST_SendQuery;
  301.                                 end;
  302.                             end else begin
  303.                                 err := -6;
  304.                             end;
  305.                         end;
  306.                     end;
  307.                     ST_SendSOCKS:begin
  308.                         if TransportGetConnectionState(tref) = T_Established then begin
  309.                             if TransportCharsAvailable(tref) >= SizeOf(socksresult) then begin
  310.                                 err := TransportReceive(tref, @socksresult, SizeOf(socksresult), received);
  311.                                 if (err = noErr) & (received <> SizeOf(socksresult)) &  (socksresult.cmd <> socks_result) then begin
  312.                                     err := -2;
  313.                                 end;
  314.                                 if err = noErr then begin
  315.                                     err := SendQuery;
  316.                                     state := ST_SendQuery;
  317.                                 end;
  318.                             end;
  319.                         end else begin
  320.                             err := -7;
  321.                         end;
  322.                     end;
  323.                     ST_SendQuery:begin
  324.                         tstate := TransportGetConnectionState(tref);
  325.                         count := Min(TransportCharsAvailable(tref),SizeOf(space));
  326.                         if (tstate <> T_Dead) & (tstate <> T_Bored) & ((tstate <> T_PleaseClose) | (count > 0))then begin
  327.                             if count>0 then begin
  328.                                 err := TransportReceive(tref, @space, count, received);
  329.                                 if err = noErr then begin
  330.                                     count := NetToMac(@space,received);
  331.                                     err:=PtrAndHand(@space,query_result,count);
  332.                                 end;
  333.                             end;
  334.                         end else begin
  335.                             if tstate = T_PleaseClose then begin
  336.                                 TransportSendClose(tref);
  337.                             end;
  338.                             GetDateTime(date);
  339.                             prefs.SetTagLong(PC_LastSIVC,date);
  340.                             ProcessResult;
  341.                             if (manual_state <> MS_Doing) then begin
  342.                                 prefs.SetTagLong(PC_LastCheckSIVCQuantum, GetThisQuantum);
  343.                             end;
  344.                             state := ST_WaitClose;
  345.                             junk := WritePrefsData;
  346.                         end;
  347.                     end;
  348.                     ST_WaitClose:begin
  349.                         tstate := TransportGetConnectionState(tref);
  350.                         if (tstate = T_Dead) or (tstate = T_Bored) then begin
  351.                             err := -3;
  352.                         end;
  353.                     end;
  354.                 end;
  355.             end;
  356.             if err <> noErr then begin
  357.                 ReleaseConnection;
  358.                 idle_til := TickCount + idle_til_period;
  359.                 state := ST_None;
  360.                 if (manual_state = MS_Doing) then begin
  361.                     manual_state := MS_None;
  362.                     if mcresult_callback <> nil then begin
  363.                         mcresult_callback(err, false, nil, '');
  364.                         mcresult_callback := nil;
  365.                     end;
  366.                 end;
  367.             end;
  368.         end;
  369.     end;
  370.     
  371.     function CanManualQuery:Boolean;
  372.     begin
  373.         CanManualQuery := (manual_state = MS_None) & (state <> ST_Finished);
  374.     end;
  375.     
  376.     procedure ManualQuery(mcresult: SIVCManualQueryCallBack);
  377.     begin
  378.         if CanManualQuery then begin
  379.             mcresult_callback := mcresult;
  380.             manual_state := MS_Want;
  381.         end else begin
  382.             if mcresult <> nil then begin
  383.                 mcresult(aspServerBusy,false,nil,'');
  384.             end;
  385.         end;
  386.     end;
  387.  
  388.     function InitSIVC(var msg: integer): OSStatus;
  389.         var
  390.             bndl:Handle;
  391.             date:longint;
  392.             junk: OSErr;
  393.     begin
  394.         msg := msg; { Unused }
  395.         sivc_dnr := nil;
  396.         state := ST_None;
  397.         tref := nil;
  398.         idle_til := TickCount;
  399.         GetVersion(vers);
  400.         app_creator := '????';
  401.         bndl := Get1Resource('BNDL', 128);
  402.         if (bndl <> nil) & (bndl^ <> nil) & (GetHandleSize(bndl) >= 4) then begin
  403.             BlockMove(bndl^, @app_creator[1], 4);
  404.         end;
  405.         query_result:= NewHandle(0);
  406.         GetDateTime(date);
  407.         SetDefaultLong(PC_FirstCheckSIVC,date);
  408.         SetDefaultLong(PC_LastCheckSIVCQuantum,-1234);
  409.         SetDefaultLong(PC_CheckSIVCPeriod,10080); { 1 week }
  410.         SetDefaultLong(PC_LastSIVC,bad_date);
  411.         SetDefaultLong(PC_SIVCUsers,-1);
  412.         first_ever_sivc := not prefs.ExistsTag(PC_UseSIVC);
  413.         junk := WritePrefsData;
  414.         InitSIVC := noErr;
  415.     end;
  416.     
  417.     procedure FinishSIVC;
  418.     begin
  419.         ReleaseConnection;
  420.         state := ST_Finished;
  421.         DisposeHandle(query_result);
  422.     end;
  423.         
  424.     procedure ConfigureSIVC(newversion : SIVCNewVersionCallBack; getsocks:SIVCGetSOCKSServerCallBack);
  425.     begin
  426.         newversion_callback := newversion;
  427.         getsocks_callback := getsocks;
  428.     end;
  429.     
  430.     procedure StartupSIVC;
  431.     begin
  432.         StartupTransport;
  433.         StartupTranslateISO;
  434.         SetStartup(InitSIVC, nil, 0, FinishSIVC);
  435.     end;
  436.     
  437. end.
  438.